package com.magenta.maxoptra.yandex.json.parsers;

import com.magenta.maxoptra.dto.GeoLocationRecord;
import com.magenta.maxoptra.gis.GeoException;
import com.magenta.maxoptra.gis.GeoRoute;
import com.magenta.maxoptra.gis.GeographicCoordinates;
import com.magenta.maxoptra.gis.utils.DateTimeHelper;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import java.util.ArrayList;
import java.util.List;

/**
 * @author Zaur Muhametgaleev
 * @version 12/20/11 12:06 PM
 * @see "jira task MRS-4161: Add support of Yandex geo provider"
 * @since Maxoptra 3 (GT)
 */
public class RoutingJSONParser {
    private static final String STAGES = "stages";
    private static final String DISTANCE = "distance";
    private static final String DURATION = "duration";
    private static final String SEGMENTS = "segments";
    private static final String LON_LAT = "ll";

    public List<GeoLocationRecord> extractRoutePoints(String requestResult) throws GeoException {
        List<GeoLocationRecord> result = new ArrayList<GeoLocationRecord>();

        try {
            JSONObject o = new JSONObject(requestResult);
            Object stagesObj = o.get(STAGES);
            if (stagesObj instanceof JSONArray) {
                Object stages = ((JSONArray) stagesObj).get(0);
                if (stages instanceof JSONObject) {
                    // extract middle points
                    Object segmentsObj = ((JSONObject) stages).get(SEGMENTS);
                    if (segmentsObj instanceof JSONArray) {
                        JSONArray segments = (JSONArray) segmentsObj;
                        for (int i = 0; i < segments.length(); i++) {
                            Object segmObj = segments.get(i);
                            if (segmObj instanceof JSONObject) {
                                JSONObject segm = (JSONObject) segmObj;
                                Object coordinatesObj = segm.get(LON_LAT);
                                if (coordinatesObj instanceof JSONArray) {
                                    JSONArray coords = (JSONArray) coordinatesObj;
                                    Double longitude = (Double) coords.get(0);
                                    Double latitude = (Double) coords.get(1);

                                    result.add(new GeoLocationRecord(longitude, latitude));
                                }
                            }
                        }
                    }
                }
            }
        } catch (JSONException e) {
            throw new GeoException(e.toString());
        }

        return result;
    }

    public GeoRoute extractDistanceAndDuration(String requestResult,
                                               GeographicCoordinates from,
                                               GeographicCoordinates to) throws GeoException {
        try {
            JSONObject o = new JSONObject(requestResult);
            Object stagesObj = o.get(STAGES);
            if (stagesObj instanceof JSONArray) {
                Object detailsObj = ((JSONArray) stagesObj).get(0);
                if (detailsObj instanceof JSONObject) { // extract middle points
                    JSONObject details = (JSONObject) detailsObj;
                    Object distanceObj = details.get(DISTANCE);
                    double distance = getDouble(distanceObj);
                    distance /= 1000d;

                    double dblDuration = getDouble(details.get(DURATION));
                    long duration = (long) (dblDuration * DateTimeHelper.MSECS_IN_SECOND);

                    return new GeoRoute(distance, duration, from, to);
                }
            }
        } catch (JSONException e) {
            throw new GeoException("Distance or duration not found");
        }

        return null;
    }

    private Double getDouble(Object obj){
        return (obj instanceof Integer) ? ((Integer) obj).doubleValue() : (Double)obj;
    }
}
